.type = CALLBACKTYPE_failsafe,
.address = { __KERNEL_CS, (unsigned long)failsafe_callback },
};
- struct xennmi_callback cb;
+ struct callback_register nmi_cb = {
+ .type = CALLBACKTYPE_nmi,
+ .address = { __KERNEL_CS, (unsigned long)nmi },
+ };
if (xen_feature(XENFEAT_auto_translated_physmap) &&
xen_start_info->shared_info < xen_start_info->nr_pages) {
failsafe.address.cs, failsafe.address.eip);
BUG_ON(ret);
- cb.handler_address = (unsigned long)&nmi;
- HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
+ if (ret == -ENOSYS) {
+ struct xennmi_callback cb;
+
+ cb.handler_address = nmi_cb.address.eip;
+ ret = HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+ }
+ BUG_ON(ret);
if (HYPERVISOR_xen_version(XENVER_platform_parameters,
&pp) == 0)
.address = (unsigned long)system_call,
};
#ifdef CONFIG_X86_LOCAL_APIC
- struct xennmi_callback cb;
+ struct callback_register nmi_cb = {
+ .type = CALLBACKTYPE_nmi,
+ .address = (unsigned long)nmi,
+ };
#endif
ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event);
BUG_ON(ret);
#ifdef CONFIG_X86_LOCAL_APIC
- cb.handler_address = (unsigned long)&nmi;
- HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
+ if (ret == -ENOSYS) {
+ struct xennmi_callback cb;
+
+ cb.handler_address = nmi_cb.address;
+ ret = HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+ }
+ BUG_ON(ret);
#endif
}
#include <xen/irq.h>
#include <xen/symbols.h>
#include <xen/reboot.h>
+#include <xen/nmi.h>
#include <asm/current.h>
#include <asm/flushtlb.h>
#include <asm/hvm/hvm.h>
v->arch.guest_context.failsafe_callback_eip = reg->address.eip;
break;
+ case CALLBACKTYPE_nmi:
+ ret = register_guest_nmi_callback(reg->address.eip);
+ break;
+
default:
ret = -EINVAL;
break;
switch ( unreg->type )
{
+ case CALLBACKTYPE_nmi:
+ ret = unregister_guest_nmi_callback();
+ break;
+
default:
ret = -EINVAL;
break;
#include <xen/console.h>
#include <xen/sched.h>
#include <xen/reboot.h>
+#include <xen/nmi.h>
#include <asm/current.h>
#include <asm/flushtlb.h>
#include <asm/msr.h>
v->arch.guest_context.syscall_callback_eip = reg->address;
break;
+ case CALLBACKTYPE_nmi:
+ ret = register_guest_nmi_callback(reg->address);
+ break;
+
default:
ret = -EINVAL;
break;
switch ( unreg->type )
{
+ case CALLBACKTYPE_nmi:
+ ret = unregister_guest_nmi_callback();
+ break;
+
default:
ret = -EINVAL;
break;
return -ENOSYS;
}
-long do_nmi_op(unsigned int cmd, GUEST_HANDLE(void) arg)
+long register_guest_nmi_callback(unsigned long address)
{
struct vcpu *v = current;
struct domain *d = current->domain;
+
+ if ( (d->domain_id != 0) || (v->vcpu_id != 0) )
+ return -EINVAL;
+
+ v->nmi_addr = address;
+#ifdef CONFIG_X86
+ /*
+ * If no handler was registered we can 'lose the NMI edge'. Re-assert it
+ * now.
+ */
+ if ( d->shared_info->arch.nmi_reason != 0 )
+ set_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
+#endif
+
+ return 0;
+}
+
+long unregister_guest_nmi_callback(void)
+{
+ struct vcpu *v = current;
+
+ v->nmi_addr = 0;
+
+ return 0;
+}
+
+long do_nmi_op(unsigned int cmd, GUEST_HANDLE(void) arg)
+{
struct xennmi_callback cb;
long rc = 0;
switch ( cmd )
{
case XENNMI_register_callback:
- rc = -EINVAL;
- if ( (d->domain_id != 0) || (v->vcpu_id != 0) )
- break;
-
rc = -EFAULT;
if ( copy_from_guest(&cb, arg, 1) )
break;
-
- v->nmi_addr = cb.handler_address;
-#ifdef CONFIG_X86
- /*
- * If no handler was registered we can 'lose the NMI edge'. Re-assert
- * it now.
- */
- if ( d->shared_info->arch.nmi_reason != 0 )
- set_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
-#endif
- rc = 0;
+ rc = register_guest_nmi_callback(cb.handler_address);
break;
case XENNMI_unregister_callback:
- v->nmi_addr = 0;
+ rc = unregister_guest_nmi_callback();
break;
default:
rc = -ENOSYS;
#define CALLBACKTYPE_event 0
#define CALLBACKTYPE_failsafe 1
#define CALLBACKTYPE_syscall 2 /* x86_64 only */
+#define CALLBACKTYPE_nmi 4
/*
* Register a callback.
#include <asm/nmi.h>
+/**
+ * register_guest_nmi_callback
+ *
+ * The default NMI handler passes the NMI to a guest callback. This
+ * function registers the address of that callback.
+ */
+extern long register_guest_nmi_callback(unsigned long address);
+
+/**
+ * unregister_guest_nmi_callback
+ *
+ * Unregister a guest NMI handler.
+ */
+extern long unregister_guest_nmi_callback(void);
+
#endif /* __XEN_NMI_H__ */